package com.flow.asyncflow.core.utils.save;

import com.flow.asyncflow.core.annotation.NodeInfo;
import com.flow.asyncflow.core.entity.config.AsyncFlowInfo;
import com.flow.asyncflow.core.entity.core.AsyncFlowBaseContext;
import com.flow.asyncflow.core.entity.core.AsyncFlowNodeResponse;
import com.flow.asyncflow.core.entity.core.AsyncFlowRequest;
import com.flow.asyncflow.core.entity.sql.ExecuteSql;
import com.flow.asyncflow.core.enums.ExecuteEnum;
import com.flow.asyncflow.core.utils.beanutils.AsyncFlowBeanUtils;
import com.flow.asyncflow.core.utils.log.asyncflowlog.AsyncFlowCommon_Log;
import com.flow.asyncflow.core.utils.msg.AsyncFlowSendMsg;
import com.flow.asyncflow.core.utils.sql.AsyncFlowSqlMapper;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.util.StopWatch;

import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;

@NodeInfo(name = "保存")
public class BaseSave {


    /**
     * 数据源
     */
    private static Map<String, SqlSessionFactory> stringSqlSessionFactoryMap = null;


    public BaseSave() {
        if (stringSqlSessionFactoryMap == null) {
            stringSqlSessionFactoryMap = new HashMap<>();
        }

    }

    /**
     * 执行保存
     *
     * @param asyncFlowRequest      请求采纳数
     * @param asyncFlowData         上下文
     * @param asyncFlowResponseCode 返回参数
     * @param timeConsuming         时间明细
     * @return AsyncFlowNodeResponse
     */
    public AsyncFlowNodeResponse execute(AsyncFlowRequest asyncFlowRequest, AsyncFlowBaseContext asyncFlowData, int asyncFlowResponseCode, AsyncFlowInfo asyncFlowInfo, LinkedHashMap<ExecuteEnum, Long> timeConsuming) {
        AsyncFlowNodeResponse asyncFlowNodeResponse;
        Date startTime = new Date();
        StopWatch sw = new StopWatch();
        sw.start(ExecuteEnum.Save.getMsg() + "-开始");
        asyncFlowNodeResponse = execute(asyncFlowRequest, asyncFlowData, asyncFlowResponseCode, asyncFlowInfo);
        AsyncFlowCommon_Log.AddAsyncFlowLog(asyncFlowRequest, asyncFlowNodeResponse, asyncFlowData, new BaseSave(), startTime, ExecuteEnum.Save, false);
        sw.stop();
        long time = sw.getTotalTimeMillis();
        timeConsuming.put(ExecuteEnum.Save, time);
        return asyncFlowNodeResponse;
    }

    /**
     * 执行保存
     *
     * @param asyncFlowRequest      请求采纳数
     * @param asyncFlowData         上下文
     * @param asyncFlowResponseCode 返回参数
     * @return AsyncFlowNodeResponse
     */
    private <TAsyncContext> AsyncFlowNodeResponse execute(AsyncFlowRequest asyncFlowRequest, AsyncFlowBaseContext asyncFlowData, int asyncFlowResponseCode, AsyncFlowInfo asyncFlowInfo) {
        AsyncFlowNodeResponse asyncFlowNodeResponse = new AsyncFlowNodeResponse();
        asyncFlowNodeResponse.setCode(200);
        asyncFlowNodeResponse.setMsg("成功");
        if (asyncFlowData.getExecuteSQLs().size() <= 0) {
            return asyncFlowNodeResponse;
        }
        Map<String, List<ExecuteSql>> executeSQLs = asyncFlowData.getExecuteSQLs().stream().collect(Collectors.groupingBy(ExecuteSql::getDbname));

        for (Map.Entry<String, List<ExecuteSql>> entry : executeSQLs.entrySet()) {
            AsyncFlowNodeResponse subAsyncFlowNodeResponse;
            //获取数据源
            setStringSqlSessionFactoryMap(asyncFlowData, entry.getKey());
            subAsyncFlowNodeResponse = executeSql(asyncFlowRequest, entry.getKey(), entry.getValue(), asyncFlowData, asyncFlowInfo, asyncFlowResponseCode);
            if (subAsyncFlowNodeResponse.getCode() != 200) {
                asyncFlowNodeResponse.setCode(subAsyncFlowNodeResponse.getCode());
                asyncFlowNodeResponse.setMsg(subAsyncFlowNodeResponse.getMsg());
                return asyncFlowNodeResponse;
            }

        }

        return asyncFlowNodeResponse;
    }


    private AsyncFlowNodeResponse executeSql(AsyncFlowRequest request, String dbname, List<ExecuteSql> executeSQLs, AsyncFlowBaseContext asyncData, AsyncFlowInfo orderFlowInfo, int asyncFlowResponseCode) {
        StringBuilder executeSqlRes = new StringBuilder();
        StringBuilder sqlBuilderLog = new StringBuilder();

        AsyncFlowNodeResponse response = new AsyncFlowNodeResponse(200, "成功");
        if (executeSQLs == null || executeSQLs.size() == 0) {
            response.setMsg(executeSqlRes.append(dbname).append("-无执行语句；").toString());
            return response;
        }
        SqlSessionFactory sqlSessionFactory = stringSqlSessionFactoryMap.get(dbname);
        if (sqlSessionFactory == null) {
            response.setMsg(executeSqlRes.append(dbname).append("-未获取到数据库连接池；").toString());
            return response;
        }

        try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
            AsyncFlowSqlMapper sqlMapper = new AsyncFlowSqlMapper(sqlSession);
            String testLog = "";
            int insert = 0;
            int update = 0;
            try {
                sqlSession.getConnection().setAutoCommit(false);
                for (ExecuteSql executeSql : executeSQLs) {
                    //执行失败时，对于非必须执行的SQL直接跳过，不执行
                    if (asyncFlowResponseCode != 200&&!executeSql.isMustExecute()) {
                        continue;
                    }
                    sqlBuilderLog.append(executeSql.getExecuteSqlLog());
                    //当前操作是拿线上数据在本地调试测试，本地调试无需执行数据库操作
                    if (orderFlowInfo.isTest() && orderFlowInfo.getEvn().equals("test")) {
                        testLog = "当前操作是拿线上数据在本地Debug，数据库无需执行操作";
                        continue;
                    }
                    if (executeSql.getType() == 1) {
                        int i = sqlMapper.insert(executeSql.getExecuteSql(), executeSql.getParamsList());
                        insert = insert + i;
                    }
                    if (executeSql.getType() == 2) {
                        int i = sqlMapper.update(executeSql.getExecuteSql(), executeSql.getParamsList());
                        update = update + i;
                    }
                }
                if (insert + update > 0) {
                    sqlSession.getConnection().commit();
                    executeSqlRes.append(dbname).append("库插入【").append(insert).append("】条数据；").append("更新【").append(update).append("】条数据；");
                }
                executeSqlRes.append(testLog);
                response.setMsg(executeSqlRes.toString());
                AsyncFlowCommon_Log.AddAsyncFlowDetailLog(asyncData, "BaseSave", dbname, sqlBuilderLog.toString(), executeSqlRes.toString(), true);
            } catch (Exception exception) {
                String s = AsyncFlowSendMsg.buildErrorMsg(request, exception, "执行基础保存---[" + dbname + "]库SQL回滚", asyncData.getAsyncFlowInfo());
                AsyncFlowSendMsg.sendQYWXMsg(orderFlowInfo.getFlowMaintainName(),s,orderFlowInfo.getNodeArmUrl());
                try {
                    sqlSession.getConnection().rollback();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                response.setMsg(dbname + "库SQL回滚");
                response.setCode(100);
                return response;
            }
        }
        return response;
    }


    /**
     * 获取数据源
     *
     * @param dbname 数据库名称
     */
    private void setStringSqlSessionFactoryMap(AsyncFlowBaseContext asyncData, String dbname) {
        if (stringSqlSessionFactoryMap.containsKey(dbname)) {
            return;
        }
        String sqlSessionFactoryName = asyncData.getDataBaseInfo().get(dbname);
        SqlSessionFactory sessionFactory = (SqlSessionFactory) AsyncFlowBeanUtils.getBean(sqlSessionFactoryName);
        stringSqlSessionFactoryMap.put(dbname, sessionFactory);
    }
}
